#include "cmanagedclient.h"
#include "scenerenderer/cscenerenderer.h"
#include <X11/Xatom.h>
#include <buola/algorithm/container.h>
#include "decorations/cbardecoration.h"
#include "decorations/cshadowdecoration.h"
#include <buola/widgets/cmenubar.h>
#include <buola/gui/cmenu.h>
#include "ceventmanager.h"

namespace buola { namespace bwm {

CManagedClient::CManagedClient(Window pID,const XWindowAttributes &pXAttrs)
    :   CClient(pID,pXAttrs)
    ,   mWMState(gui::x11::icccm::WMSTATE_WITHDRAWN)
    ,   mManagedDecoration(nullptr)
{
    mDrag.mState=gui::DRAG_NONE;

    mResize.mPending=false;
    mResize.mCounterValue=5;
    mResize.mCounter=nullptr;
    mResize.mAlarm=nullptr;
}

CManagedClient::~CManagedClient()
{
    erase_all_equal(gRoot->mManagedClients,this);
}
    
void CManagedClient::StartManaging()
{
    if(GetFlag(FLAG_MANAGED)) return;

    InitGrabs();
    ReadCommonProperties();
    ReadAllProperties();

    if(mNET.mState&gui::x11::icccm::NETSTATE_STICKY)
        SetFlag(FLAG_STICKY);
    if(mNET.mState&gui::x11::icccm::NETSTATE_ABOVE)
        SetFlag(FLAG_ABOVE);
    if(mNET.mState&gui::x11::icccm::NETSTATE_BELOW)
        SetFlag(FLAG_BELOW);

    if(mNET.mStrut!=CRect_i(0,0,0,0))
    {
        gRoot->WMIncStrut((int)(mNET.mStrut.l),(int)(mNET.mStrut.t),
                          (int)(mNET.mStrut.r),(int)(mNET.mStrut.b));
    }

    CalcDesktops();
    
    SetAllProperties();

    CalcVisibleName(false);
    CalcPriority(false);
    InitGeometry();

    if(!mDecoration)
        CreateDecoration();

    PlaceWindow();

    Show();

    gRoot->mClientsStack.push_back(this);
    gRoot->mManagedClients.push_back(this);
    SetFlag(FLAG_MANAGED);

    if(gui::x11::get_default_x11_display()->HasWindowProperty(mID,gui::x11::get_default_x11_display()->Atoms().mBuolaDockWindow))
        SetFlag(FLAG_IS_BUOLA_DOCK);

    if(gRoot->IsStarted())
    {
        if(CanBeActivated(false))
            gRoot->WMActivate(this);
        else
            gRoot->WMRestack();
    }

    gRoot->mEventManager->SelectManagerEvents(this);
}

void CManagedClient::StopManaging()
{
    if(!GetFlag(FLAG_MANAGED)) return;

    ReleaseGrabs();
    UnsetAllProperties();

    erase_all_equal(gRoot->mClientsStack,this);
    erase_all_equal(gRoot->mManagedClients,this);

    UnsetFlag(FLAG_MANAGED);

    gRoot->mEventManager->DeselectManagerEvents(this);
}

void CManagedClient::InitGrabs()
{
    XGrabButton(gui::x11::get_default_x11_display()->GetDisplay(),AnyButton,AnyModifier,mID,
                False,ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
                GrabModeSync,GrabModeAsync,None,None);
}

void CManagedClient::ReleaseGrabs()
{
    XUngrabButton(gui::x11::get_default_x11_display()->GetDisplay(),AnyButton,AnyModifier,mID);
}

void CManagedClient::CalcVisibleName(bool pNotify)
{
    std::wstring lOldName=mVisibleName;

    if(mNET.mName.length())
        mVisibleName=mNET.mName;
    else if(mICCCM.mName.length())
        mVisibleName=mICCCM.mName;
    else
        mVisibleName=L"unknown window";

    if(!mICCCM.mClientMachine.empty())
    {
        if(mICCCM.mClientMachine!=get_host_name())
        {
            mVisibleName+=L" (on ";
            mVisibleName+=utf32(mICCCM.mClientMachine);
            mVisibleName+=L')';
        }
    }

    //make it unique
    bool lFound=false;

    for(int i=0;i<gRoot->mManagedClients.size();i++)
    {
        if(gRoot->mManagedClients[i]==this) continue;
        if(gRoot->mManagedClients[i]->mVisibleName==mVisibleName)
        {
            lFound=true;
            break;
        }
    }

    if(lFound) //other client has same visible name
    {
        std::wstring lNewLabel;

        for(int j=2;lFound;j++)
        {
            lNewLabel=mVisibleName;
            lNewLabel+=L" <";
            lNewLabel+=to_wstring(j);
            lNewLabel+='>';

            lFound=false;

            for(int i=0;i<gRoot->mManagedClients.size();i++)
            {
                if(gRoot->mManagedClients[i]==this) continue;
                if(gRoot->mManagedClients[i]->mVisibleName==lNewLabel)
                {
                    lFound=true;
                    break;
                }
            }
        }

        mVisibleName=lNewLabel;
    }

    if(lOldName!=mVisibleName)
    {
        gui::x11::icccm::write_net_wm_visible_name(mID,mVisibleName);
        if(pNotify)
        {
            if(mManagedDecoration)
                mManagedDecoration->OnLabelChanged();
        }
    }
}

void CManagedClient::CalcPriority(bool pUpdate)
{
    EZPriority lPriority;

    if(IsActive()&&(mState&EState::FULLSCREEN))
    {
        lPriority=ZP_FULLSCREEN;
    }
    else if(mWindowType==gui::EWindowType::DOCK)
    {
        lPriority=ZP_DOCK;
    }
    else if(mWindowType==gui::EWindowType::DESKTOP)
    {
        lPriority=ZP_DESKTOP;
    }
    else if(GetFlag(FLAG_ABOVE))
    {
        lPriority=ZP_ABOVE;
    }
    else if(GetFlag(FLAG_BELOW))
    {
        lPriority=ZP_BELOW;
    }
    else
    {
        lPriority=ZP_NORMAL;
    }

    if(mZPriority!=lPriority)
    {
        mZPriority=lPriority;

        if(pUpdate)
            gRoot->WMRestack();
    }
}

img::CPicture CManagedClient::CalcIcon(const CSize_d &pSize)
{
    return img::CPicture();
/*
    if(!mNET.mIcons.size()&&!mNET.mIcon) return nullptr;

    int lBestSizeIndex=-1;
    CSize_d lBestSize=CSize(0,0);

    for(int i=0;i<mNET.mIcons.size();i++)
    {
        CSize_d lSize=mNET.mIcons[i]->GetSize();
        if(lSize==pSize)
            return mNET.mIcons[i];

        if(lBestSize<pSize) //nothing really good found
        {
            if(lSize>lBestSize)
            {
                lBestSizeIndex=i;
                lBestSize=lSize;
            }
        }
        else
        {
            if(lSize>=pSize&&lSize<lBestSize)
            {
                lBestSizeIndex=i;
                lBestSize=lSize;
            }
        }
    }

    //we didn't find the exact size... create it
    if(mNET.mIcon)
    {
        PImage lWMIcon=mNET.mIcon->GetImage((int)pSize.x);
        mNET.mIcons.push_back(lWMIcon);
        return lWMIcon;
    }
    else
    {
        if(lBestSizeIndex<0) return nullptr;

        PImage lWMIcon=new CImage;
        lWMIcon->Create(mNET.mIcons[lBestSizeIndex]);
        lWMIcon->Scale(CSize_i(pSize));
        mNET.mIcons.push_back(lWMIcon);
        return lWMIcon;
    }
*/
    
}

///////////////////////////////////////////////////////////////////
//                                                               //
//                  management of other classes                  //
//                                                               //
///////////////////////////////////////////////////////////////////

void CManagedClient::CreateDecoration()
{
    if(mWindowType==gui::EWindowType::DOCK||mWindowType==gui::EWindowType::DESKTOP) //no decoration at all
        return;

    if(mWindowType!=gui::EWindowType::SPLASH&&(!(mMotif.mFlags&MOTIF_DECORATIONS)||mMotif.mDecorations))
    {
        CBarDecoration *lDecoration=new CBarDecoration(this);
        mManagedDecoration=lDecoration;
        mDecoration=lDecoration;
    
        lDecoration->Create(mPhysicalPos,mPhysicalSize,mXPos);
        lDecoration->eDrag.Connect(&CManagedClient::DragStart,this,_2,_1,_3,true);
        lDecoration->eDragCancel.Connect(&CManagedClient::DragEnd,this);
        lDecoration->eDamage.Connect(&CClient::DamageDecoration,this);
        lDecoration->eActivate.Connect(&CManagedClient::OnDecorationActivate,this);
        lDecoration->eShowMenu.Connect(&CManagedClient::OnDecorationShowMenu,this,_1);
        lDecoration->eButton.Connect(&CManagedClient::OnDecorationButton,this,_1);
    
        CRect_i lFrameExtent=mManagedDecoration->GetFrameExtent();
        gui::x11::icccm::write_net_frame_extents(mID,CRect_i(-lFrameExtent.l,-lFrameExtent.t,
                                                              lFrameExtent.r,lFrameExtent.b));
    }
    else
    {
        //should create a shadow decoration here
        mDecoration=new CShadowDecoration(this);
    }
}

///////////////////////////////////////////////////////////////////
//                                                               //
//                       size and position                       //
//                                                               //
///////////////////////////////////////////////////////////////////

void CManagedClient::InitGeometry()
{
    XSetWindowAttributes lXAttrs;
    lXAttrs.bit_gravity=NorthWestGravity;
    lXAttrs.win_gravity=NorthWestGravity;
    XChangeWindowAttributes(gui::x11::get_default_x11_display()->GetDisplay(),mID,
            CWBitGravity|CWWinGravity,&lXAttrs);

    if(mICCCM.mSizeHints.mFlags&(gui::x11::icccm::HINT_USERPOS|gui::x11::icccm::HINT_PROGRAMPOS))
        mLogicalPos=mPhysicalPos;
    else
        mLogicalPos=CPoint_i(nUndefined);

    mLogicalSize=mPhysicalSize-(2*mBorderWidth);
    
    CheckSize();
}

bool CManagedClient::ShouldPlaceWindow()
{
    if(mLogicalPos.Undefined()) return true;
    if(mLogicalPos.x<0&&mLogicalPos.y<0) return true;
    if(mLogicalPos.x==0&&mLogicalPos.y==0&&mWindowType!=
            gui::EWindowType::DOCK&&mWindowType!=gui::EWindowType::DESKTOP)
        return true;
    return false;
}

void CManagedClient::PlaceWindow()
{
    if(mLogicalSize.x<=0)
    {
        mLogicalSize={300,300};
    }

    if(ShouldPlaceWindow())
    {
        CSize_i lSize=mLogicalSize;
        if(mManagedDecoration)
            lSize+=mManagedDecoration->GetFrameExtent().Size();
        
        CClient *lTransientFor=mTransientFor?gRoot->GetClient(mTransientFor):nullptr;
        if(lTransientFor)
        {
            msg_info() << "placing with transient" << lTransientFor->GetPhysicalPos() << "\n";
            mLogicalPos=lTransientFor->GetPhysicalPos()+(lTransientFor->GetPhysicalSize()-lSize)/2;
        }
        else
        {
            CRect_i lLimits=gRoot->GetWorkArea(mDesktop)-lSize;

            double lEmptiest=-1;
            int lEmptiestX=0;
            int lEmptiestY=0;

            int lInc=min(5*(gRoot->mManagedClients.size()+1),std::size_t(50));

            for(int x=(int)lLimits.l;x<=(int)lLimits.r;x+=lInc)
            {
                for(int y=(int)lLimits.t;y<=(int)lLimits.b;y+=lInc)
                {
                    CRect_i lCurRect(CPoint_i(x,y),lSize);
                    int lArea=0;

                    for(int i=0;i<gRoot->mManagedClients.size();i++)
                    {
                        CManagedClient *lU=gRoot->mManagedClients[i];
                        if(lU==this) continue;
                        if(lU->mLogicalPos.Undefined()) continue;

                        CRect_i lOtherRect;
                        if(lU->mManagedDecoration)
                        {
                            lOtherRect=CRect_i(lU->mPhysicalPos,lU->mPhysicalSize)+lU->mManagedDecoration->GetFrameExtent();
                        }
                        else
                        {
                            lOtherRect={lU->mPhysicalPos,lU->mPhysicalSize};
                        }

                        msg_debug<25>() << lCurRect << lOtherRect << "\n";
                        lArea+=intersection(lOtherRect,lCurRect).Area();
                    }

                    if(lEmptiest<0||lArea<lEmptiest)
                    {
                        lEmptiest=lArea;
                        lEmptiestX=x;
                        lEmptiestY=y;
                    }

                    if(!lEmptiest) break;
                }
                if(!lEmptiest) break;
            }

            mLogicalPos=CPoint_i(lEmptiestX,lEmptiestY);
        }

        if(mManagedDecoration)
            mLogicalPos-=mManagedDecoration->GetFrameExtent().TopLeft();
    }

    CheckSize();
    MoveResizeClient(mLogicalPos,mLogicalSize);
}

void CManagedClient::CheckSize()
{
    if(mICCCM.mSizeHints.mFlags&gui::x11::icccm::HINT_MIN)
    {
        mLogicalSize.ConstrainMin(mICCCM.mSizeHints.mMin);
    }
    if(mICCCM.mSizeHints.mFlags&gui::x11::icccm::HINT_MAX)
    {
        mLogicalSize.ConstrainMax(mICCCM.mSizeHints.mMax);
    }
    if(mICCCM.mSizeHints.mFlags&gui::x11::icccm::HINT_RESIZE)
    {
        if(mICCCM.mSizeHints.mFlags&gui::x11::icccm::HINT_BASE)
            mLogicalSize-=mICCCM.mSizeHints.mBase;

        mLogicalSize.x-=(int)mLogicalSize.x%(int)mICCCM.mSizeHints.mInc.x;
        mLogicalSize.y-=(int)mLogicalSize.y%(int)mICCCM.mSizeHints.mInc.y;

        if(mICCCM.mSizeHints.mFlags&gui::x11::icccm::HINT_BASE)
            mLogicalSize+=mICCCM.mSizeHints.mBase;
    }

    const CSize_d &lRootSize=gRoot->GetSize();

    if(!mLogicalPos.Undefined())
    {
        if(mLogicalPos.x<-mLogicalSize.x+1)
            mLogicalPos.x=lRootSize.x/2-mLogicalSize.x/2;
        else if(mLogicalPos.x>=gRoot->GetSize().x)
            mLogicalPos.x=lRootSize.x/2-mLogicalSize.x/2;
        if(mLogicalPos.y<-mLogicalSize.y+1)
            mLogicalPos.y=lRootSize.y/2-mLogicalSize.y/2;
        else if(mLogicalPos.y>=gRoot->GetSize().y)
            mLogicalPos.y=lRootSize.y/2-mLogicalSize.y/2;
    }
}

bool CManagedClient::SetLogicalSize(const CSize_i &pSize)
{
//The decoration calls this function when it tries to change the window size
    CSize_i lOldSize=mLogicalSize;

    mLogicalSize=pSize;
    CheckSize();

    return(mLogicalSize!=lOldSize);
}

bool CManagedClient::SetLogicalPos(const CPoint_i &pPos)
{
    CPoint_i lOldPos=mLogicalPos;

    mLogicalPos=pPos;

    return(mLogicalPos!=lOldPos);
}

void CManagedClient::IncLogicalSize(CSize_i &pDelta)
{
    CSize_i lOldSize=mLogicalSize;
    mLogicalSize+=pDelta;
    CheckSize();

    pDelta=mLogicalSize-lOldSize;
}

void CManagedClient::IncLogicalPos(CPoint_i &pDelta)
{
    CPoint_i lOldPos=mLogicalPos;
    mLogicalPos+=pDelta;

    pDelta=mLogicalPos-lOldPos;
}

////////////////////////////////////////////////////////////
/////////////// managing window properties /////////////////
////////////////////////////////////////////////////////////

void CManagedClient::ReadAllProperties()
{
    mICCCM.mName=gui::x11::icccm::read_wm_name(mID);
    gui::x11::icccm::read_wm_hints(mID,mICCCM.mWMHints);
    gui::x11::icccm::read_wm_normal_hints(mID,mICCCM.mSizeHints);
    mICCCM.mClass=gui::x11::icccm::read_wm_class(mID);
    mICCCM.mProtocols=gui::x11::icccm::read_wm_protocols(mID);
    mICCCM.mClientMachine=gui::x11::icccm::read_wm_client_machine(mID);
    
    mNET.mName=gui::x11::icccm::read_net_wm_name(mID);
    mNET.mState=gui::x11::icccm::read_net_wm_state(mID);
    mNET.mStrut=gui::x11::icccm::read_net_wm_strut(mID);
    if(!gui::x11::icccm::read_net_wm_icon(mID,mNET.mIcons))
        mNET.mIcon=gui::CIcon::Get("gnome-terminal");
    else
        mNET.mIcon=nullptr;
    mNET.mIconGeometry=gui::x11::icccm::read_net_wm_icon_geometry(mID);

    gui::x11::icccm::read_motif_hints(mID,mMotif);
}

void CManagedClient::SetAllProperties()
{
    gui::x11::icccm::write_net_wm_desktop(mID,mDesktop);
}

void CManagedClient::UnsetAllProperties()
{
}

///////////////////////////////////////////////////////////////////
//                                                               //
//                   window manager operations                   //
//                                                               //
///////////////////////////////////////////////////////////////////

void CManagedClient::GiveFocus()
{
    XSetInputFocus(gui::x11::get_default_x11_display()->GetDisplay(),mID,
                            RevertToPointerRoot,CurrentTime);
}

bool CManagedClient::CanBeActivated(bool pIconic)
{
    if(!WantsFocus()) return false;
    if(!pIconic&&mWMState==gui::x11::icccm::WMSTATE_ICONIC) return false;
    if(!IsOnDesktop(gRoot->GetActiveDesktop())) return false;
    return true;
}

void CManagedClient::Activate()
{
    if(mWMState==gui::x11::icccm::WMSTATE_ICONIC)
        Show();

    if(WantsFocus())
        GiveFocus();

    if(mManagedDecoration)
        mManagedDecoration->OnClientActivated(true);
}

void CManagedClient::DeActivate()
{
    if(mManagedDecoration)
        mManagedDecoration->OnClientActivated(false);
}

bool CManagedClient::CanClose()
{
    if(mWindowType==gui::EWindowType::DOCK) return false;
    if(mWindowType==gui::EWindowType::DESKTOP) return false;
    return true;
}

void CManagedClient::Close()
{
    if (mICCCM.mProtocols&gui::x11::icccm::PROTOCOL_DELETE)
    {
        gui::x11::get_default_x11_display()->SendClientMessage(mID,mID,
                gui::x11::get_default_x11_display()->Atoms().mProtocols,gui::x11::get_default_x11_display()->Atoms().mDeleteWindow,CurrentTime);
    }
    else
    {
        XKillClient(gui::x11::get_default_x11_display()->GetDisplay(),mID);
    }
}

void CManagedClient::Show()
{
    if(mWMState==gui::x11::icccm::WMSTATE_NORMAL) return;

    ShowClient(true);

    if(mWMState==gui::x11::icccm::WMSTATE_ICONIC)
    {
        StartAnimation(ANIM_DEICONIFY,CRect_d(mNET.mIconGeometry));
    }

    mWMState=gui::x11::icccm::WMSTATE_NORMAL;

    UpdateState();
}

void CManagedClient::Withdraw()
{
    if(mWMState==gui::x11::icccm::WMSTATE_WITHDRAWN) return;

    mWMState=gui::x11::icccm::WMSTATE_WITHDRAWN;

    if(IsActive())
        gRoot->WMRevert();

    UpdateState();

    StopManaging();
}

void CManagedClient::Iconify()
{
    if(mWMState==gui::x11::icccm::WMSTATE_ICONIC) return;

    ShowClient(false);

    mWMState=gui::x11::icccm::WMSTATE_ICONIC;
    mState|=EState::ICONIC;

    if(IsActive())
        gRoot->WMRevert();

    UpdateState();

    StartAnimation(ANIM_ICONIFY,CRect_d(mNET.mIconGeometry));
}

void CManagedClient::Fullscreen(bool pB)
{
    if(pB==(mState&EState::FULLSCREEN)) return;

    if(pB)
    {
        mState|=EState::FULLSCREEN;

        MoveResizeClient(CPoint_i(0,0),CSize_i(gRoot->GetSize()));
    }
    else
    {
        mState&=(~EState::FULLSCREEN);

        MoveResizeClient(mLogicalPos,mLogicalSize);
    }

    UpdateState();
}

void CManagedClient::Maximize(EState pMax)
{
    if((mState&EState::MAXIMIZED)==pMax) return;

    mState=(mState&(~EState::MAXIMIZED))|pMax;

    if(pMax==EState::NONE)
    {
        MoveResizeClient(mLogicalPos,mLogicalSize);
    }
    else
    {
        CRect_i lWorkArea=gRoot->GetWorkArea(gRoot->GetActiveDesktop());
        CPoint_i lMaxPos(lWorkArea.TopLeft()-mManagedDecoration->GetFrameExtent().TopLeft());
        CSize_i lMaxSize(lWorkArea.Size()-mManagedDecoration->GetFrameExtent().Size());

        if(pMax==EState::MAXHORZ)
        {
            MoveResizeClient(CPoint_i(lMaxPos.x,mLogicalPos.y),
                            CSize_i(lMaxSize.x,mLogicalSize.y));
        }
        else if(pMax==EState::MAXVERT)
        {
            MoveResizeClient(CPoint_i(mLogicalPos.x,lMaxPos.y),
                            CSize_i(mLogicalSize.x,lMaxSize.y));
        }
        else
        {
            MoveResizeClient(lMaxPos,lMaxSize);
        }
    }

    UpdateState();
}

void CManagedClient::Shade(bool pB)
{
    if(pB==(mState&EState::SHADED)) return;

    if(pB)
    {
        mState|=EState::SHADED;
    }
    else
    {
        mState&=(~EState::SHADED);
    }

    UpdateState();
}

void CManagedClient::Sticky(bool pB)
{
    if(pB)
    {
        SetFlag(FLAG_STICKY);
    }
    else
    {
        UnsetFlag(FLAG_STICKY);
        mDesktop=gRoot->GetActiveDesktop();
    }

    CalcDesktops();
    UpdateState();
}

void CManagedClient::ToDesktop(unsigned int pDesktop)
{
    if(pDesktop>1000)
        pDesktop=0xffffffff;

    if(pDesktop!=mDesktop)
    {
        mDesktop=pDesktop;
        gui::x11::icccm::write_net_wm_desktop(mID,mDesktop);
        if(mManagedDecoration)
            mManagedDecoration->OnDesktopSwitched();
    }

    CalcDesktops();
    MoveClient(mPhysicalPos);
}

void CManagedClient::UpdateState()
{
    gui::x11::icccm::write_wm_state(mID,mWMState);

    mNET.mState&=~(gui::x11::icccm::NETSTATE_STICKY|gui::x11::icccm::NETSTATE_ABOVE|gui::x11::icccm::NETSTATE_BELOW|gui::x11::icccm::NETSTATE_FULLSCREEN);
    
    if(mFlags&FLAG_STICKY)
        mNET.mState|=gui::x11::icccm::NETSTATE_STICKY;
    if(mFlags&FLAG_ABOVE)
        mNET.mState|=gui::x11::icccm::NETSTATE_ABOVE;
    if(mFlags&FLAG_BELOW)
        mNET.mState|=gui::x11::icccm::NETSTATE_BELOW;
    if(mState&EState::FULLSCREEN)
        mNET.mState|=gui::x11::icccm::NETSTATE_FULLSCREEN;
    
    gui::x11::icccm::write_net_wm_state(mID,mNET.mState);
}

bool CManagedClient::ShouldCirculate()
{
    if(mWindowType==gui::EWindowType::DOCK) return false;
    if(mWindowType==gui::EWindowType::DESKTOP) return false;
    return true;
}


///////////////////////////////////////////////////////////////////
//                                                               //
//                     dragging the window                       //
//                                                               //
///////////////////////////////////////////////////////////////////

void CManagedClient::DragStart(const CPoint_d &pPos,gui::EDragState pState,gui::EMouseButton pButton,bool pGrab)
{
    if(mDrag.mState) return;
    if(!pState) return;
    if(GetState()&EState::MAXIMIZED) return;

    mDrag.mState=pState;
    mDrag.mPos=pPos;
    mDrag.mOriginalPos=pPos;
    mDrag.mButton=pButton;
    mDrag.mGrab=pGrab;

    Cursor lCursor;

    if(pState&(gui::DRAG_CTRLALTLB|gui::DRAG_CTRLALTRB))
    {
        lCursor=gui::CPointer::GetStock(gui::CPointer::STOCK_INVISIBLE)->GetID();
        mDrag.mPos.x=gRoot->GetSize().x/2;
        mDrag.mPos.y=gRoot->GetSize().y/2;
        XWarpPointer(gui::x11::get_default_x11_display()->GetDisplay(),gRoot->GetID(),gRoot->GetID(),
                0,0,0,0,(int)mDrag.mPos.x,(int)mDrag.mPos.y);
    }
    else
    {
        lCursor=gui::CPointer::GetStock(gui::CPointer::STOCK_CROSS)->GetID();
    }

    if(pGrab)
    {
        XGrabPointer(gui::x11::get_default_x11_display()->GetDisplay(),mID,False,ButtonPressMask|
                    ButtonReleaseMask|PointerMotionMask,GrabModeAsync,
                    GrabModeAsync,None,lCursor,CurrentTime);
    }

    StartAnimationDrag(pPos,pState);
}

void CManagedClient::DragStep(const CPoint_d &pPos)
{
    if(!mDrag.mState) return;

    CPoint_i lDelta(pPos-mDrag.mPos);

    if(!lDelta.x&&!lDelta.y) return;

    if(mDrag.mState==gui::DRAG_MOVE)
    {
        IncLogicalPos(lDelta);
        MoveClient(mLogicalPos);
        StepAnimationDrag(CPoint_d(lDelta),CSize_d(0,0));

        mDrag.mPos+=CPoint_d(lDelta);
    }
    else if(mDrag.mState&(gui::DRAG_CTRLALTLB|gui::DRAG_CTRLALTRB))
    {
        gRoot->GetSceneRenderer()->DragStep(mDrag.mState,CPoint_d(lDelta));

        XWarpPointer(gui::x11::get_default_x11_display()->GetDisplay(),gRoot->GetID(),gRoot->GetID(),
                0,0,0,0,(int)mDrag.mPos.x,(int)mDrag.mPos.y);
    }
    else
    {
        CPoint_i lDeltaMove(0,0);
        CSize_i lDeltaSize(0,0);

        if(mDrag.mState==gui::DRAG_WEST)
        {
            lDeltaSize.x=-lDelta.x;
            IncLogicalSize(lDeltaSize);
            lDeltaMove.x=-lDeltaSize.x;
            lDelta.x=-lDeltaSize.x;
        }
        else if(mDrag.mState==(gui::DRAG_WEST|gui::DRAG_NORTH))
        {
            lDeltaSize.x=-lDelta.x;
            lDeltaSize.y=-lDelta.y;
            IncLogicalSize(lDeltaSize);
            lDeltaMove.x=-lDeltaSize.x;
            lDeltaMove.y=-lDeltaSize.y;
            lDelta.x=-lDeltaSize.x;
            lDelta.y=-lDeltaSize.y;
        }
        else if(mDrag.mState==gui::DRAG_NORTH)
        {
            lDeltaSize.y=-lDelta.y;
            IncLogicalSize(lDeltaSize);
            lDeltaMove.y=-lDeltaSize.y;
            lDelta.y=-lDeltaSize.y;
        }
        else if(mDrag.mState==(gui::DRAG_NORTH|gui::DRAG_EAST))
        {
            lDeltaSize.y=-lDelta.y;
            lDeltaSize.x=lDelta.x;
            IncLogicalSize(lDeltaSize);
            lDeltaMove.y=-lDeltaSize.y;
            lDelta.x=lDeltaSize.x;
            lDelta.y=-lDeltaSize.y;
        }
        else if(mDrag.mState==gui::DRAG_EAST)
        {
            lDeltaSize.x=lDelta.x;
            IncLogicalSize(lDeltaSize);
            lDelta.x=lDeltaSize.x;
        }
        else if(mDrag.mState==(gui::DRAG_EAST|gui::DRAG_SOUTH))
        {
            lDeltaSize.y=lDelta.y;
            lDeltaSize.x=lDelta.x;
            IncLogicalSize(lDeltaSize);
            lDelta.x=lDeltaSize.x;
            lDelta.y=lDeltaSize.y;
        }
        else if(mDrag.mState==gui::DRAG_SOUTH)
        {
            lDeltaSize.y=lDelta.y;
            IncLogicalSize(lDeltaSize);
            lDelta.y=lDeltaSize.y;
        }
        else if(mDrag.mState==(gui::DRAG_SOUTH|gui::DRAG_WEST))
        {
            lDeltaSize.y=lDelta.y;
            lDeltaSize.x=-lDelta.x;
            IncLogicalSize(lDeltaSize);
            lDeltaMove.x=-lDeltaSize.x;
            lDelta.x=-lDeltaSize.x;
            lDelta.y=lDeltaSize.y;
        }

        if(lDeltaSize.x||lDeltaSize.y)
        {
            if(mICCCM.mProtocols&gui::x11::icccm::PROTOCOL_SYNCREQUEST)
            {
                if(!mResize.mCounter)
                {
                    int *lID;
                    int **lPID=&lID;
                    int lCount=gui::x11::get_default_x11_display()->GetWindowProperty(mID,
                            gui::x11::get_default_x11_display()->Atoms().mNetWMSyncRequestCounter,
                            XA_CARDINAL,(void**)lPID,1);
                    if(lCount==1)
                    {
                        mResize.mCounter=new gui::x11::CX11SyncCounter(*lID,false);
                        mResize.mCounterValue=mResize.mCounter->Get();
                    }
                    else
                    {
                        msg_error() << "Can't find resize counter\n";
                    }
                }
                if(mResize.mCounter)
                {
                    mResize.mCounterValue++;
                    if(!mResize.mAlarm)
                    {
                        mResize.mAlarm=new gui::x11::CX11SyncAlarm(*mResize.mCounter,
                                mResize.mCounterValue,gui::x11::CX11SyncCounter::SYNC_NONE,1);
                        mResize.mAlarm->sTriggered.Connect(&CManagedClient::OnResizeAlarm,this);
                    }
                    gui::x11::get_default_x11_display()->SendClientMessage(mID,mID,
                            gui::x11::get_default_x11_display()->Atoms().mProtocols,gui::x11::get_default_x11_display()->Atoms().mNetWMSyncRequest,CurrentTime,
                            mResize.mCounterValue&0xffffffff,
                            mResize.mCounterValue>>32);

                    SetFlag(FLAG_WAITINGRESIZEALARM);
                }
            }

            if(lDeltaMove.x||lDeltaMove.y)
            {
                IncLogicalPos(lDeltaMove);
                MoveResizeClient(mLogicalPos,mLogicalSize);
            }
            else
            {
                ResizeClient(mLogicalSize);
            }

//          StepAnimationDrag(lDeltaMove,lDeltaSize);
        }

        mDrag.mPos+=CPoint_d(lDelta);
    }
}

void CManagedClient::DragEnd()
{
    if(!mDrag.mState) return;

    if(mDrag.mState==gui::DRAG_CTRLALTLB||mDrag.mState==gui::DRAG_CTRLALTRB)
    {
        XWarpPointer(gui::x11::get_default_x11_display()->GetDisplay(),gRoot->GetID(),gRoot->GetID(),
                0,0,0,0,(int)mDrag.mOriginalPos.x,(int)mDrag.mOriginalPos.y);
        gRoot->GetSceneRenderer()->DragFinish(mDrag.mState);
    }

    if(mDrag.mGrab)
    {
        XUngrabPointer(gui::x11::get_default_x11_display()->GetDisplay(),CurrentTime);
    }

    mDrag.mState=gui::DRAG_NONE;
}

///////////////////////////////////////////////////////////////////
//                                                               //
//                       event handlers                          //
//                                                               //
///////////////////////////////////////////////////////////////////

void CManagedClient::OnMapNotify(bool pWMStarting)
{
    SetFlag(FLAG_MAPPED);

    if(!GetFlag(FLAG_MANAGED)) //this should only happen on startup. otherwise the map request will come first
    {
        StartManaging();
    }

    StartComposer();

    if(!pWMStarting)
    {
        SetFlag(CClient::FLAG_DAMAGED);
        if(mAnimating!=ANIM_DEICONIFY)
            StartAnimation(ANIM_FADEIN);
    }
    else
    {
        mEffOpacity=mOpacity;
    }

    if(mManagedDecoration)
        mManagedDecoration->OnClientMapped();

    DetermineRegions();
    DetermineMode();
}

void CManagedClient::OnUnmapNotify(bool pSynthetic)
{
    if(GetFlag(FLAG_MAPPED))
    {
        //the client unmapped a managed window -> change to withdrawn
        Withdraw();
    }
    else //we already knew about it, so we unmapped it ourselves
    {
        if(pSynthetic) //the client wants the window withdrawn
        {
            Withdraw();
        }
    }

    UnsetFlag(FLAG_MAPPED);

    if(mManagedDecoration)
        mManagedDecoration->OnClientUnmapped();

    if(mAnimating!=ANIM_ICONIFY)
        StartAnimation(ANIM_FADEOUT);
}

void CManagedClient::OnDestroyNotify()
{
    mID=0;
    mXDamage=0;

    gRoot->WMIncStrut((int)-mNET.mStrut.l,(int)-mNET.mStrut.t,
                            (int)-mNET.mStrut.r,(int)-mNET.mStrut.b);

    if(IsActive())
    {
        gRoot->WMActivate(nullptr);
        gRoot->WMRevert();
    }

    StartAnimation(ANIM_FADEOUT);
}

void CManagedClient::OnPropertyNotify(XPropertyEvent *pE)
{
    if(!GetFlag(FLAG_MANAGED)) return;

    Atom lAtom = pE->atom;
    bool lDeleted=(pE->state==PropertyDelete);

    if(lAtom==XA_WM_NAME)
    {
        if(lDeleted)
            mICCCM.mName.clear();
        else
            mICCCM.mName=gui::x11::icccm::read_wm_name(mID);

        CalcVisibleName(true);
    }
    else if(lAtom==gui::x11::get_default_x11_display()->Atoms().mNetWMName)
    {
        if(lDeleted)
            mNET.mName.clear();
        else
            mNET.mName=gui::x11::icccm::read_net_wm_name(mID);

        CalcVisibleName(true);
    }
    else if(lAtom==XA_WM_TRANSIENT_FOR)
    {
        msg_warn() << "Changing transient in managed window " << mID << "\n";
    }
    else if(lAtom==XA_WM_NORMAL_HINTS)
    {
        gui::x11::icccm::read_wm_normal_hints(mID,mICCCM.mSizeHints);
        CheckSize();
    }
    else if(lAtom==gui::x11::get_default_x11_display()->Atoms().mNetWMWindowOpacity)
    {
        msg_warn() << "Setting opacity for window " << mID << "\n";
        //TODO:mNET.mOpacity=gui::x11::icccm::read_net_wm_window_opacity(mID);
    }
    else if(lAtom==gui::x11::get_default_x11_display()->Atoms().mNetWMIconGeometry)
    {
        mNET.mIconGeometry=gui::x11::icccm::read_net_wm_icon_geometry(mID);
    }
    else if(lAtom==gui::x11::get_default_x11_display()->Atoms().mNetWMIcon)
    {
        if(!gui::x11::icccm::read_net_wm_icon(mID,mNET.mIcons))
            mNET.mIcon=gui::CIcon::Get("gnome-terminal");
        else
            mNET.mIcon=nullptr;
    }
    else if(lAtom==gui::x11::get_default_x11_display()->Atoms().mNetWMStrut)
    {
        CRect_i lOldStrut=mNET.mStrut;
        mNET.mStrut=gui::x11::icccm::read_net_wm_strut(mID);
        
        if(lOldStrut!=mNET.mStrut)
        {
            gRoot->WMIncStrut(mNET.mStrut.l-lOldStrut.l,mNET.mStrut.t-lOldStrut.t,
                              mNET.mStrut.r-lOldStrut.r,mNET.mStrut.b-lOldStrut.b);
        }
    }
    else
    {
        msg_warn() << "Changed client property " << mID << " " << gui::x11::get_default_x11_display()->GetAtomName(lAtom) << "\n";
    }
}

void CManagedClient::OnButtonDown(const CPoint_d &pP,gui::EMouseButton pButton,int pMods)
{
    bool lReplay=true;

    if((pMods&KEYMOD_ALT)&&(pMods&KEYMOD_CONTROL))
    {
//         if(pButton&gui::EMouseButton::)
//         {
// //          gRoot->mSceneRenderer->StartZoom(1.5,0.2,true);
//         }
//         else if(pButton&gui::MOUSE_ZDOWN)
//         {
// //          gRoot->mSceneRenderer->StartZoom(1.0/1.5,0.2,true);
//         }
        if(pButton==gui::EMouseButton::LEFT)
        {
            DragStart(pP,gui::DRAG_CTRLALTLB,pButton,true);
        }
        else if(pButton==gui::EMouseButton::RIGHT)
        {
            DragStart(pP,gui::DRAG_CTRLALTRB,pButton,true);
        }
        lReplay=false;
    }
    else if(mWindowType==gui::EWindowType::DESKTOP)
    {
        if(pButton&(gui::EMouseButton::LEFT|gui::EMouseButton::MIDDLE|gui::EMouseButton::RIGHT))
        {
            if(WantsFocus()&&!IsActive())
                gRoot->WMActivate(this);
        }
    }
    else if(mWindowType!=gui::EWindowType::DOCK)
    {
        if(pButton&(gui::EMouseButton::LEFT|gui::EMouseButton::MIDDLE|gui::EMouseButton::RIGHT))
        {
            if(WantsFocus()&&!IsActive())
                gRoot->WMActivate(this);
        }

        if(pButton==gui::EMouseButton::LEFT&&(pMods&KEYMOD_ALT))
        {
            DragStart(pP,gui::DRAG_MOVE,pButton,true);
            lReplay=false;
        }
        if(pButton==gui::EMouseButton::RIGHT&&(pMods&KEYMOD_ALT))
        {
            DragStart(pP,gui::DRAG_EAST|gui::DRAG_SOUTH,pButton,true);
            lReplay=false;
        }
    }

    if(lReplay)
        XAllowEvents(gui::x11::get_default_x11_display()->GetDisplay(),ReplayPointer,CurrentTime);
    else
        XAllowEvents(gui::x11::get_default_x11_display()->GetDisplay(),SyncPointer,CurrentTime);
}

void CManagedClient::OnButtonUp(const CPoint_d &pP,gui::EMouseButton pButton,int pMods)
{
    if(mDrag.mState)
    {
        if(mResize.mPending)
        {
            DragStep(mResize.mPoint);
            mResize.mPending=false;
        }

        DragEnd();
    }
}

void CManagedClient::OnMouseMove(const CPoint_d &pP)
{
    if(mDrag.mState)
    {
        if(GetFlag(FLAG_WAITINGRESIZEALARM))
        {
            mResize.mPoint=pP;
            mResize.mPending=true;
        }
        else
        {
            DragStep(pP);
        }
    }
}

void CManagedClient::OnConfigureRequest(XConfigureRequestEvent *pE)
{
    int lMask=pE->value_mask;

    if(lMask&(CWX|CWY))
    {
        CPoint_i lPoint(pE->x,pE->y);
        if(mManagedDecoration)
            lPoint+=mManagedDecoration->GetFrameExtent().TopLeft();
        if(lPoint.x<0) lPoint.x=0;
        if(lPoint.y<0) lPoint.y=0;
        SetLogicalPos(lPoint);
        CheckSize();
        MoveClient(mLogicalPos);
    }
    if(lMask&(CWWidth|CWHeight))
    {
        CSize_i lSize(pE->width,pE->height);
        const CSize_d &lRootSize=gRoot->GetSize();
        if(lSize.x>lRootSize.x) lSize.x=lRootSize.x;
        if(lSize.y>lRootSize.y) lSize.y=lRootSize.y;
        SetLogicalSize(lSize);
        ResizeClient(lSize);
    }
    if(lMask&CWBorderWidth)
    {
        //we don't usually accept ugly borders
    }
    if(lMask&CWStackMode)
    {
        if(pE->detail==Above)
        {
            gRoot->WMRaise(this);
        }
        else if(pE->detail==Below)
        {
            gRoot->WMLower(this);
        }
    }
    if(lMask&CWSibling)
    {
        msg_debug<5>() << "OnConfigureRequest sibling\n";
    }
}

void CManagedClient::OnMapRequest()
{
    if(GetFlag(FLAG_MANAGED))
    {
        Show();
    }
    else
    {
        StartManaging();
    }
}

bool CManagedClient::OnClientMessage(XClientMessageEvent *pE)
{
    if(pE->message_type==gui::x11::get_default_x11_display()->Atoms().mNetActiveWindow)
    {
        gRoot->WMActivate(this);
        if(mAnimating!=ANIM_DEICONIFY)
            StartAnimation(ANIM_ACTIVATE);
    }
    else if(pE->message_type==gui::x11::get_default_x11_display()->Atoms().mNetWMState)
    {
        int lOp=pE->data.l[0];

        gui::x11::icccm::ENetState lNew=mNET.mState;

        for(int i=1;i<=2;i++)
        {
            if(!pE->data.l[i]) continue;

            if((Atom)pE->data.l[i]==gui::x11::get_default_x11_display()->Atoms().mNetWMStateModal)
            {
                if(lOp==0||(lOp==2&&(lNew&gui::x11::icccm::NETSTATE_MODAL)))
                {
                    lNew&=~gui::x11::icccm::NETSTATE_MODAL;
                }
                else
                {
                    lNew|=gui::x11::icccm::NETSTATE_MODAL;
                }
            }
            else if((Atom)pE->data.l[i]==gui::x11::get_default_x11_display()->Atoms().mNetWMStateSticky)
            {
                if(lOp==0||(lOp==2&&(lNew&gui::x11::icccm::NETSTATE_STICKY)))
                {
                    lNew&=~gui::x11::icccm::NETSTATE_STICKY;
                }
                else
                {
                    lNew|=gui::x11::icccm::NETSTATE_STICKY;
                }
            }
            else if((Atom)pE->data.l[i]==gui::x11::get_default_x11_display()->Atoms().mNetWMStateMaxVert)
            {
                if(lOp==0||(lOp==2&&(lNew&gui::x11::icccm::NETSTATE_MAXVERT)))
                {
                    lNew&=~gui::x11::icccm::NETSTATE_MAXVERT;
                }
                else
                {
                    lNew|=gui::x11::icccm::NETSTATE_MAXVERT;
                }
            }
            else if((Atom)pE->data.l[i]==gui::x11::get_default_x11_display()->Atoms().mNetWMStateMaxHorz)
            {
                if(lOp==0||(lOp==2&&(lNew&gui::x11::icccm::NETSTATE_MAXHORZ)))
                {
                    lNew&=~gui::x11::icccm::NETSTATE_MAXHORZ;
                }
                else
                {
                    lNew|=gui::x11::icccm::NETSTATE_MAXHORZ;
                }
            }
            else if((Atom)pE->data.l[i]==gui::x11::get_default_x11_display()->Atoms().mNetWMStateFullScreen)
            {
                if(lOp==0||(lOp==2&&(lNew&gui::x11::icccm::NETSTATE_FULLSCREEN)))
                {
                    lNew&=~gui::x11::icccm::NETSTATE_FULLSCREEN;
                }
                else
                {
                    lNew|=gui::x11::icccm::NETSTATE_FULLSCREEN;
                }
            }
            else if((Atom)pE->data.l[i]==gui::x11::get_default_x11_display()->Atoms().mNetWMStateShaded)
            {
                if(lOp==0||(lOp==2&&(lNew&gui::x11::icccm::NETSTATE_SHADED)))
                {
                    lNew&=~gui::x11::icccm::NETSTATE_SHADED;
                }
                else
                {
                    lNew|=gui::x11::icccm::NETSTATE_SHADED;
                }
            }
            else if((Atom)pE->data.l[i]==gui::x11::get_default_x11_display()->Atoms().mNetWMStateSkipTaskbar)
            {
                if(lOp==0||(lOp==2&&(lNew&gui::x11::icccm::NETSTATE_SKIPTASKBAR)))
                {
                    lNew&=~gui::x11::icccm::NETSTATE_SKIPTASKBAR;
                }
                else
                {
                    lNew|=gui::x11::icccm::NETSTATE_SKIPTASKBAR;
                }
            }
            else if((Atom)pE->data.l[i]==gui::x11::get_default_x11_display()->Atoms().mNetWMStateSkipPager)
            {
                if(lOp==0||(lOp==2&&(lNew&gui::x11::icccm::NETSTATE_SKIPPAGER)))
                {
                    lNew&=~gui::x11::icccm::NETSTATE_SKIPPAGER;
                }
                else
                {
                    lNew|=gui::x11::icccm::NETSTATE_SKIPPAGER;
                }
            }
            else if((Atom)pE->data.l[i]==gui::x11::get_default_x11_display()->Atoms().mNetWMStateAbove)
            {
                if(lOp==0||(lOp==2&&(lNew&gui::x11::icccm::NETSTATE_ABOVE)))
                {
                    lNew&=~gui::x11::icccm::NETSTATE_ABOVE;
                }
                else
                {
                    lNew|=gui::x11::icccm::NETSTATE_ABOVE;
                }
            }
            else if((Atom)pE->data.l[i]==gui::x11::get_default_x11_display()->Atoms().mNetWMStateBelow)
            {
                if(lOp==0||(lOp==2&&(lNew&gui::x11::icccm::NETSTATE_BELOW)))
                {
                    lNew&=~gui::x11::icccm::NETSTATE_BELOW;
                }
                else
                {
                    lNew|=gui::x11::icccm::NETSTATE_BELOW;
                }
            }
        }

        if(lNew!=mNET.mState)
        {
            gui::x11::icccm::ENetState lDiff=lNew^mNET.mState;

            if(lDiff&(gui::x11::icccm::NETSTATE_MAXHORZ|gui::x11::icccm::NETSTATE_MAXVERT))
            {
                EState lMax=EState::NONE;

                if(lNew&gui::x11::icccm::NETSTATE_MAXHORZ)
                    lMax|=EState::MAXHORZ;
                if(lNew&gui::x11::icccm::NETSTATE_MAXVERT)
                    lMax|=EState::MAXVERT;

                Maximize(lMax);
            }
            if(lDiff&gui::x11::icccm::NETSTATE_FULLSCREEN)
            {
                Fullscreen(lNew&gui::x11::icccm::NETSTATE_FULLSCREEN);
            }
            if(lDiff&gui::x11::icccm::NETSTATE_SHADED)
            {
                Shade(lNew&gui::x11::icccm::NETSTATE_SHADED);
            }
            if(lDiff&gui::x11::icccm::NETSTATE_STICKY)
            {
                Sticky(lNew&gui::x11::icccm::NETSTATE_STICKY);
            }

            CalcPriority(true);
        }
    }
    else if(pE->message_type==gui::x11::get_default_x11_display()->Atoms().mChangeState)
    {
        Atom lState=(Atom)pE->data.l[0];

        if(lState==NormalState)
        {
            Show();
        }
        else if(lState==IconicState)
        {
            Iconify();
        }
        else
        {
            msg_warn() << "wrong state in received ChangeState message\n";
        }
    }
    else if(pE->message_type==gui::x11::get_default_x11_display()->Atoms().mNetCloseWindow)
    {
        Close();
    }
    else if(pE->message_type==gui::x11::get_default_x11_display()->Atoms().mNetWMMoveResize)
    {
        gui::EDragState lType=gui::DRAG_NONE;
        switch(pE->data.l[2])
        {
        case _NET_WM_MOVERESIZE_SIZE_TOPLEFT:
            lType=gui::DRAG_WEST|gui::DRAG_NORTH;
            break;
        case _NET_WM_MOVERESIZE_SIZE_TOP:
            lType=gui::DRAG_NORTH;
            break;
        case _NET_WM_MOVERESIZE_SIZE_TOPRIGHT:
            lType=gui::DRAG_EAST|gui::DRAG_NORTH;
            break;
        case _NET_WM_MOVERESIZE_SIZE_RIGHT:
            lType=gui::DRAG_EAST;
            break;
        case _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT:
            lType=gui::DRAG_EAST|gui::DRAG_SOUTH;
            break;
        case _NET_WM_MOVERESIZE_SIZE_BOTTOM:
            lType=gui::DRAG_SOUTH;
            break;
        case _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT:
            lType=gui::DRAG_WEST|gui::DRAG_SOUTH;
            break;
        case _NET_WM_MOVERESIZE_SIZE_LEFT:
            lType=gui::DRAG_WEST;
            break;
        case _NET_WM_MOVERESIZE_MOVE:
            lType=gui::DRAG_MOVE;
            break;
        }

        if(lType)
        {
            DragStart(CPoint_d(pE->data.l[0],pE->data.l[1]),lType,
                gui::x11::CX11Dispatcher::TranslateButtonFromX(pE->data.l[3]),true);
        }
    }
    else if(pE->message_type==gui::x11::get_default_x11_display()->Atoms().mNetWMDesktop)
    {
        ToDesktop(pE->data.l[0]);
    }
    else
    {
        return true;
    }
    //Message from the client... it wants something
    return false;
}

void CManagedClient::OnResizeAlarm()
{
//  msg_info() << "Resize Alarm " << mID << "\n";

    UnsetFlag(FLAG_WAITINGRESIZEALARM);

    OnGeometryChanged(true);

    if(mResize.mPending)
    {
        DragStep(mResize.mPoint);
        mResize.mPending=false;
    }
}

void CManagedClient::OnDecorationShowMenu(const CPoint_d &pPoint)
{
    gui::PMenu lMenu=new gui::CMenu;

    lMenu->Add(gui::new_menu_item(L"iconify"))->eTriggered.Connect(&CManagedClient::Iconify,this);

    lMenu->Add(gui::new_menu_item(L"maximize"))->
                        eTriggered.Connect(&CManagedClient::OnDecorationButton,this,CManagedDecoration::BUTTON_MAXIMIZE);
    lMenu->Add(gui::new_menu_item(L"shade"))->
                        eTriggered.Connect(&CManagedClient::OnDecorationButton,this,CManagedDecoration::BUTTON_SHADE);
    lMenu->Add(gui::new_menu_item(L"full screen"))->
                        eTriggered.Connect(&CManagedClient::OnDecorationButton,this,CManagedDecoration::BUTTON_FULLSCREEN);
/*
    lMenu->AddItem(ID_DECO_MOVE,L"move");
    lMenu->AddItem(ID_DECO_RESIZE,L"resize");
    lMenu->AddSeparator();
    lMenu->AddItem(ID_DECO_ABOVE,L"stay above");
    lMenu->AddItem(ID_DECO_BELOW,L"stay below");
*/
    lMenu->Add(gui::new_menu_item(L"sticky"))->
                        eTriggered.Connect(&CManagedClient::OnDecorationButton,this,CManagedDecoration::BUTTON_STICKY);
    lMenu->AddSeparator();
    gui::PMenu lTransMenu=lMenu->AddSubMenu(L"opacity");
    gui::PMenu lDesktopMenu=lMenu->AddSubMenu(L"to desktop");
    lMenu->AddSeparator();
    lMenu->Add(gui::new_menu_item(L"close"))->eTriggered.Connect(&CManagedClient::Close,this);

    lTransMenu->Add(gui::new_menu_item(L"10%"))->eTriggered.Connect(&CClient::SetOpacity,this,0.1);
    lTransMenu->Add(gui::new_menu_item(L"20%"))->eTriggered.Connect(&CClient::SetOpacity,this,0.2);
    lTransMenu->Add(gui::new_menu_item(L"30%"))->eTriggered.Connect(&CClient::SetOpacity,this,0.3);
    lTransMenu->Add(gui::new_menu_item(L"40%"))->eTriggered.Connect(&CClient::SetOpacity,this,0.4);
    lTransMenu->Add(gui::new_menu_item(L"50%"))->eTriggered.Connect(&CClient::SetOpacity,this,0.5);
    lTransMenu->Add(gui::new_menu_item(L"60%"))->eTriggered.Connect(&CClient::SetOpacity,this,0.6);
    lTransMenu->Add(gui::new_menu_item(L"70%"))->eTriggered.Connect(&CClient::SetOpacity,this,0.7);
    lTransMenu->Add(gui::new_menu_item(L"80%"))->eTriggered.Connect(&CClient::SetOpacity,this,0.8);
    lTransMenu->Add(gui::new_menu_item(L"90%"))->eTriggered.Connect(&CClient::SetOpacity,this,0.9);
    lTransMenu->Add(gui::new_menu_item(L"100%"))->eTriggered.Connect(&CClient::SetOpacity,this,1.0);

    for(int i=0;i<gRoot->GetDesktopCount();i++)
    {
        lDesktopMenu->Add(gui::new_menu_item(gRoot->GetDesktopName(i)))->eTriggered.Connect(&CManagedClient::ToDesktop,this,i);
    }
    lDesktopMenu->AddSeparator();
    lDesktopMenu->Add(gui::new_menu_item(L"all"))->eTriggered.Connect(&CManagedClient::ToDesktop,this,0xffffffff);

    gui::PMenuBar lMenuBar=new gui::CMenuBar;
    ///\todo
    //lMenuBar->CreatePopup(nullptr,lMenu,pPoint);
    lMenuBar->Show();
}

void CManagedClient::OnDecorationButton(CManagedDecoration::EButton pButton)
{
    switch(pButton)
    {
        case CManagedDecoration::BUTTON_MAXIMIZE:
            if(GetState()&EState::MAXIMIZED)
                Maximize(EState::NONE);
            else
                Maximize();
            break;
        case CManagedDecoration::BUTTON_SHADE:
            Shade(!(GetState()&EState::SHADED));
            break;
        case CManagedDecoration::BUTTON_FULLSCREEN:
            Fullscreen(!(GetState()&EState::FULLSCREEN));
            break;
        case CManagedDecoration::BUTTON_STICKY:
            Sticky(!GetFlag(FLAG_STICKY));
            break;
        case CManagedDecoration::BUTTON_CLOSE:
            Close();
            break;
        case CManagedDecoration::BUTTON_ICONIFY:
            Iconify();
            break;
        default:
            break;
/*
        case ID_DECO_FIRSTDESKTOP ... ID_DECO_LASTDESKTOP:
            ToDesktop(pID-ID_DECO_FIRSTDESKTOP);
            break;
        case ID_DECO_ALLDESKTOPS:
            ToDesktop(0xffffffff);
            break;
*/
    }
}

void CManagedClient::OnDecorationActivate()
{
    if(WantsFocus())
        gRoot->WMActivate(this);
}

/*namespace bwm*/ } /*namespace buola*/ }
